001 /*
002 * Copyright 2005 Stephen J. McConnell.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.station.console;
020
021 import java.io.IOException;
022 import java.io.InputStreamReader;
023 import java.io.BufferedReader;
024 import java.lang.reflect.InvocationTargetException;
025 import java.net.URI;
026 import java.net.URL;
027 import java.rmi.RemoteException;
028 import java.rmi.ConnectException;
029 import java.rmi.registry.LocateRegistry;
030 import java.rmi.registry.Registry;
031 import java.rmi.server.UnicastRemoteObject;
032 import java.util.ArrayList;
033 import java.util.List;
034 import java.util.Iterator;
035 import java.util.Set;
036 import java.util.HashSet;
037 import java.util.Properties;
038
039 import net.dpml.station.Application;
040 import net.dpml.station.Manager;
041 import net.dpml.station.Station;
042 import net.dpml.station.StationException;
043 import net.dpml.station.info.StartupPolicy;
044 import net.dpml.station.ApplicationRegistry;
045 import net.dpml.station.info.ApplicationDescriptor;
046 import net.dpml.station.server.RemoteApplicationRegistry;
047 import net.dpml.station.server.OutputStreamReader;
048 import net.dpml.station.server.ErrorStreamReader;
049
050 import net.dpml.component.Provider;
051
052 import net.dpml.state.State;
053 import net.dpml.state.Operation;
054 import net.dpml.state.Transition;
055 import net.dpml.state.Interface;
056
057 import net.dpml.transit.Artifact;
058 import net.dpml.util.Logger;
059 import net.dpml.lang.PID;
060 import net.dpml.transit.Disposable;
061 import net.dpml.lang.ValueDirective;
062 import net.dpml.util.ExceptionHelper;
063 import net.dpml.util.PropertyResolver;
064
065 import net.dpml.lang.UnknownKeyException;
066 import net.dpml.lang.DuplicateKeyException;
067
068 import net.dpml.cli.Option;
069 import net.dpml.cli.Group;
070 import net.dpml.cli.CommandLine;
071 import net.dpml.cli.commandline.Parser;
072 import net.dpml.cli.util.HelpFormatter;
073 import net.dpml.cli.OptionException;
074 import net.dpml.cli.DisplaySetting;
075 import net.dpml.cli.builder.ArgumentBuilder;
076 import net.dpml.cli.builder.GroupBuilder;
077 import net.dpml.cli.builder.DefaultOptionBuilder;
078 import net.dpml.cli.builder.CommandBuilder;
079 import net.dpml.cli.option.PropertyOption;
080 import net.dpml.cli.validation.EnumValidator;
081 import net.dpml.cli.validation.URIValidator;
082 import net.dpml.cli.validation.NumberValidator;
083
084
085 /**
086 * Plugin that handles station commands.
087 *
088 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
089 * @version 1.0.0
090 */
091 public class StationPlugin implements Disposable
092 {
093 // ------------------------------------------------------------------------
094 // state
095 // ------------------------------------------------------------------------
096
097 private final Logger m_logger;
098
099 private boolean m_flag = false; // true if we have to take down the registry on exit
100
101 private ApplicationRegistry m_registry; // contains the ref to the registry used during disposal
102
103 // ------------------------------------------------------------------------
104 // constructor
105 // ------------------------------------------------------------------------
106
107 /**
108 * Creation of a new station plugin. The station plugin handles console
109 * based commmandline interaction with the application registry and a
110 * server station.
111 *
112 * @param logger the assigned logging channel
113 * @param args command line arguments
114 * @exception Exception if an error occurs during plugin establishment
115 */
116 public StationPlugin( Logger logger, String[] args ) throws Exception
117 {
118 m_logger = logger;
119
120 ClassLoader context = Station.class.getClassLoader();
121 Thread.currentThread().setContextClassLoader( context );
122
123 // log the raw arguments
124
125 if( m_logger.isDebugEnabled() )
126 {
127 logRawArguments( logger, args );
128 }
129
130 // handle commands
131
132 Parser parser = new Parser();
133 parser.setGroup( COMMAND_GROUP );
134
135 try
136 {
137 CommandLine line = parser.parse( args );
138 if( line.hasOption( HELP_COMMAND ) )
139 {
140 processHelp();
141 }
142 else if( line.hasOption( STARTUP_COMMAND ) )
143 {
144 processStartup( line );
145 }
146 else if( line.hasOption( SHUTDOWN_COMMAND ) )
147 {
148 processShutdown( line );
149 }
150 else if( line.hasOption( ADD_COMMAND ) )
151 {
152 processAddCommand( line );
153 }
154 else if( line.hasOption( SET_COMMAND ) )
155 {
156 processSetCommand( line );
157 }
158 else if( line.hasOption( INFO_COMMAND ) )
159 {
160 processInfoCommand( line );
161 }
162 else if( line.hasOption( START_COMMAND ) )
163 {
164 processStartCommand( line );
165 }
166 else if( line.hasOption( CONTROL_COMMAND ) )
167 {
168 processControlCommand( line );
169 }
170 else if( line.hasOption( STOP_COMMAND ) )
171 {
172 processStopCommand( line );
173 }
174 else if( line.hasOption( RESTART_COMMAND ) )
175 {
176 processRestartCommand( line );
177 }
178 else if( line.hasOption( REMOVE_COMMAND ) )
179 {
180 processRemoveCommand( line );
181 }
182 else
183 {
184 List options = line.getOptions();
185 Iterator iterator = options.iterator();
186 while( iterator.hasNext() )
187 {
188 Option option = (Option) iterator.next();
189 System.out.println(
190 "# UNPROCESSED OPTION: "
191 + option
192 + " ["
193 + option.getId()
194 + "]" );
195 }
196 }
197 }
198 catch( OptionException e )
199 {
200 m_logger.error( e.getMessage() );
201 }
202 }
203
204 // ------------------------------------------------------------------------
205 // Disposable
206 // ------------------------------------------------------------------------
207
208 /**
209 * Initiate disposal of the station plugin. If the pugin has established
210 * the applications registry (occurs if the station is not running as a remote
211 * process and the implementation loads the application repository).
212 */
213 public void dispose()
214 {
215 if( m_flag && ( null != m_registry ) )
216 {
217 getLogger().debug( "retracting registry from rmi" );
218 try
219 {
220 UnicastRemoteObject.unexportObject( m_registry, true );
221 m_registry = null;
222 }
223 catch( Throwable e )
224 {
225 e.printStackTrace();
226 }
227 }
228 }
229
230 // ------------------------------------------------------------------------
231 // commandline interegation
232 // ------------------------------------------------------------------------
233
234 private Manager getManager( CommandLine line ) throws Exception
235 {
236 int port = getPortValue( line, Registry.REGISTRY_PORT );
237 Registry registry = getLocalRegistry( port );
238 if( null != registry )
239 {
240 try
241 {
242 return (Manager) registry.lookup( Station.STATION_KEY );
243 }
244 catch( ConnectException e )
245 {
246 throw e;
247 }
248 catch( Exception e )
249 {
250 System.out.println( "# ERROR: " + e );
251 final String error =
252 "Unable to locate station.";
253 throw new StationException( error, e );
254 }
255 }
256 else
257 {
258 final String error =
259 "Unable to locate station.";
260 throw new StationException( error );
261 }
262 }
263
264 private URI getRegistryURI( CommandLine line )
265 {
266 if( line.hasOption( REGISTRY_URI_OPTION ) )
267 {
268 return null;
269 }
270 else
271 {
272 return (URI) line.getValue( REGISTRY_URI_OPTION, null );
273 }
274 }
275
276 private URI getConfigurationURI( CommandLine line, URI fallback )
277 {
278 if( line.hasOption( CONFIGURATION_URI_OPTION ) )
279 {
280 return fallback;
281 }
282 else
283 {
284 return (URI) line.getValue( CONFIGURATION_URI_OPTION, fallback );
285 }
286 }
287
288 /**
289 * Return a properties instance composed of the <tt>-D<key>=<value></tt>
290 * commandline arguments.
291 * @param line the commandline
292 * @return the resolved properties
293 */
294 private Properties getCommandLineProperties( CommandLine line, Properties properties )
295 {
296 Set propertyValue = line.getProperties();
297 Iterator iterator = propertyValue.iterator();
298 while( iterator.hasNext() )
299 {
300 String name = (String) iterator.next();
301 String value = line.getProperty( name );
302 properties.setProperty( name, value );
303 }
304 return properties;
305 }
306
307 /**
308 * Return the basedir option value.
309 * @param line the commandline
310 * @return the base path
311 */
312 private String getBasedir( CommandLine line, String current )
313 {
314 return (String) line.getValue( BASEDIR_OPTION, current );
315 }
316
317 /**
318 * Get the application title.
319 * @param line the commandline
320 * @param title a default title if no title specified on the commandline
321 * @return the application title
322 */
323 private String getTitle( CommandLine line, String title )
324 {
325 return (String) line.getValue( TITLE_OPTION, title );
326 }
327
328 /**
329 * Return the startup policy declared on the commandline.
330 * @param line the commandline
331 * @param policy the default policy to apply
332 */
333 private StartupPolicy getStartupPolicy( CommandLine line, StartupPolicy policy )
334 {
335 final String policyValue = (String) line.getValue( STARTUP_POLICY_OPTION, null );
336 if( null == policyValue )
337 {
338 return policy;
339 }
340 else
341 {
342 return StartupPolicy.parse( policyValue );
343 }
344 }
345
346 private int getPortValue( CommandLine line, int defaultPort )
347 {
348 if( line.hasOption( PORT_OPTION ) )
349 {
350 Number number = (Number) line.getValue( PORT_OPTION, null );
351 if( null != number )
352 {
353 return number.intValue();
354 }
355 }
356 return defaultPort;
357 }
358
359 private int getStartupTimeout( CommandLine line, int fallback )
360 {
361 if( line.hasOption( STARTUP_TIMEOUT_OPTION ) )
362 {
363 Number number = (Number) line.getValue( STARTUP_TIMEOUT_OPTION, null );
364 if( null != number )
365 {
366 return number.intValue();
367 }
368 }
369 return fallback;
370 }
371
372 private int getShutdownTimeout( CommandLine line, int fallback )
373 {
374 if( line.hasOption( SHUTDOWN_TIMEOUT_OPTION ) )
375 {
376 Number number = (Number) line.getValue( SHUTDOWN_TIMEOUT_OPTION, null );
377 if( null != number )
378 {
379 return number.intValue();
380 }
381 }
382 return fallback;
383 }
384
385 private ApplicationRegistry getApplicationRegistry( CommandLine line ) throws Exception
386 {
387 URI uri = getRegistryURI( line );
388 if( null != uri )
389 {
390 return getApplicationRegistry( uri );
391 }
392 else
393 {
394 try
395 {
396 Manager manager = getManager( line );
397 getLogger().debug( "using remote registry" );
398 return manager.getApplicationRegistry();
399 }
400 catch( Exception e )
401 {
402 getLogger().debug( "using local registry" );
403 return getApplicationRegistry( (URI) null );
404 }
405 }
406 }
407
408 // ------------------------------------------------------------------------
409 // command handling
410 // ------------------------------------------------------------------------
411
412 /**
413 * List general command help to the console.
414 * @exception IOException if an I/O error occurs
415 */
416 private void processHelp() throws IOException
417 {
418 HelpFormatter formatter = new HelpFormatter(
419 HelpFormatter.DEFAULT_GUTTER_LEFT,
420 HelpFormatter.DEFAULT_GUTTER_CENTER,
421 HelpFormatter.DEFAULT_GUTTER_RIGHT,
422 100, 50 );
423
424 formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_GROUP_OUTER );
425 formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
426 formatter.getDisplaySettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
427
428 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_OPTIONAL );
429 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_GROUP_OUTER );
430 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
431 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_OPTIONAL );
432 formatter.getFullUsageSettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
433 formatter.getFullUsageSettings().remove( DisplaySetting.DISPLAY_PARENT_CHILDREN );
434
435 formatter.getLineUsageSettings().add( DisplaySetting.DISPLAY_PROPERTY_OPTION );
436 formatter.getLineUsageSettings().add( DisplaySetting.DISPLAY_ARGUMENT_BRACKETED );
437 formatter.getLineUsageSettings().remove( DisplaySetting.DISPLAY_PARENT_CHILDREN );
438 formatter.getLineUsageSettings().remove( DisplaySetting.DISPLAY_GROUP_EXPANDED );
439
440 formatter.setGroup( COMMAND_GROUP );
441 formatter.setShellCommand( "station" );
442 formatter.print();
443 }
444
445 /**
446 * Startup the station.
447 */
448 private void processStartup( CommandLine line ) throws Exception
449 {
450 getLogger().debug( "processing startup request" );
451 int port = getPortValue( line, Registry.REGISTRY_PORT );
452 if( null != getStation( port ) )
453 {
454 final String message =
455 "Station already deployed on port: " + port;
456 getLogger().warn( message );
457 return;
458 }
459
460 ArrayList list = new ArrayList();
461 list.add( "station" );
462 list.add( "-server" );
463 list.add( "" + port );
464
465 list.add( "-Ddpml.logging.config=local:properties:dpml/station/server" );
466 list.add( "-Ddpml.subprocess=true" );
467 if( "true".equals( System.getProperty( "dpml.trace" ) ) )
468 {
469 list.add( "-trace" );
470 }
471 else if( "true".equals( System.getProperty( "dpml.debug" ) ) )
472 {
473 list.add( "-debug" );
474 }
475 Set propertyValue = line.getProperties();
476 Iterator iterator = propertyValue.iterator();
477 while( iterator.hasNext() )
478 {
479 String name = (String) iterator.next();
480 String value = line.getProperty( name );
481 list.add( "-D" + name + "=" + value );
482 }
483
484 URI uri = getRegistryURI( line );
485 if( null != uri )
486 {
487 list.add( "-registry" );
488 list.add( uri.toASCIIString() );
489 }
490 String[] args = (String[]) list.toArray( new String[0] );
491
492 String message = "server startup command:";
493 String info = getRawArguments( message, args );
494 getLogger().debug( info );
495
496 Process process = Runtime.getRuntime().exec( args, null );
497 getLogger().info( "waiting for server" );
498 OutputStreamReader output = new OutputStreamReader( getLogger(), process.getInputStream() );
499 ErrorStreamReader err = new ErrorStreamReader( getLogger(), process.getErrorStream() );
500 output.setDaemon( true );
501 err.setDaemon( true );
502 output.start();
503 err.start();
504
505 int n = 0;
506 while( ( null == getStation( port ) && n < 20 ) )
507 {
508 try
509 {
510 Thread.currentThread().sleep( 600 );
511 }
512 catch( Exception e )
513 {
514 }
515 n++;
516 }
517
518 if( null == getStation( port ) )
519 {
520 getLogger().info( "server failed to start" );
521 }
522 else
523 {
524 getLogger().info( "station started" );
525 }
526 }
527
528 private void processShutdown( CommandLine line ) throws Exception
529 {
530 try
531 {
532 Manager manager = getManager( line );
533 getLogger().info( "initiating station shutdown" );
534 try
535 {
536 manager.shutdown();
537 }
538 catch( Exception e )
539 {
540 getLogger().warn( e.getClass().getName() );
541 }
542 getLogger().info( "station shutdown complete" );
543 }
544 catch( Exception e )
545 {
546 getLogger().info( "station is not running" );
547 }
548 }
549
550 /**
551 * List application registry information.
552 * @param line the commandline
553 */
554 private void processInfoCommand( CommandLine line ) throws Exception
555 {
556 System.out.println( "" );
557 Thread.currentThread().setContextClassLoader( Provider.class.getClassLoader() );
558 Manager manager = null;
559 try
560 {
561 manager = getManager( line );
562 System.out.println( " Server is operational." );
563 try
564 {
565 String[] info = manager.getInfo();
566 for( int i=0; i<info.length; i++ )
567 {
568 String value = info[i];
569 System.out.println( " " + value );
570 }
571 }
572 catch( RemoteException e )
573 {
574 getLogger().error( "Remote exception.", e );
575 }
576 }
577 catch( Exception e )
578 {
579 System.out.println( " Server is not running." );
580 }
581
582 ApplicationRegistry registry = getApplicationRegistry( line );
583 String key = (String) line.getValue( INFO_COMMAND, null );
584
585 if( null == key )
586 {
587 StringBuffer buffer = new StringBuffer( "\n" );
588 try
589 {
590 String[] keys = registry.getKeys();
591 buffer.append( "\nProfile count: " + keys.length + "\n" );
592 for( int i=0; i<keys.length; i++ )
593 {
594 String k = keys[i];
595 ApplicationDescriptor profile =
596 registry.getApplicationDescriptor( k );
597 buffer.append(
598 "\n ("
599 + ( i+1 )
600 + ") "
601 + k
602 );
603 if( null != manager )
604 {
605 Application application = manager.getApplication( k );
606 buffer.append( "\t" + application.getProcessState() );
607 }
608 else
609 {
610 buffer.append( "\t" );
611 }
612 buffer.append( "\t" + profile.getCodeBaseURI() );
613 }
614 buffer.append( "\n" );
615 System.out.println( buffer.toString() );
616 }
617 catch( RemoteException e )
618 {
619 getLogger().error( "Remote exception.", e );
620 }
621 catch( UnknownKeyException e )
622 {
623 // ignore
624 }
625 }
626 else
627 {
628 try
629 {
630 ApplicationDescriptor profile = registry.getApplicationDescriptor( key );
631 listProfile( profile );
632 if( null != manager )
633 {
634 Application application = manager.getApplication( key );
635 PID pid = application.getPID();
636 if( null != pid )
637 {
638 //
639 System.out.println(
640 " Process: "
641 + application.getPID()
642 + " ("
643 + application.getProcessState()
644 + ")" );
645 }
646 else
647 {
648 System.out.println(
649 " Process: "
650 + application.getProcessState() );
651 }
652
653 Provider instance = application.getProvider();
654 if( null != instance )
655 {
656 State state = instance.getState();
657 System.out.println( " State: " + state );
658 Operation[] operations = state.getOperations();
659 if( operations.length > 0 )
660 {
661 System.out.println( " Operations: (" + operations.length + ")" );
662 for( int i=0; i<operations.length; i++ )
663 {
664 System.out.println( " " + operations[i] );
665 }
666 }
667 Interface[] interfaces = state.getInterfaces();
668 if( interfaces.length > 0 )
669 {
670 System.out.println( " Interfaces: (" + interfaces.length + ")" );
671 for( int i=0; i<interfaces.length; i++ )
672 {
673 System.out.println( " " + interfaces[i] );
674 }
675 }
676 Transition[] transitions = state.getTransitions();
677 if( transitions.length > 0 )
678 {
679 System.out.println( " Transitions: (" + transitions.length + ")" );
680 for( int i=0; i<transitions.length; i++ )
681 {
682 System.out.println( " " + transitions[i] );
683 }
684 }
685 }
686 }
687 }
688 catch( UnknownKeyException e )
689 {
690 getLogger().warn( "Unknown application key [" + key + "]." );
691 }
692 catch( RemoteException e )
693 {
694 getLogger().error( "Remote exception.", e );
695 }
696 }
697 }
698
699 /**
700 * Handle a request for the startup of an application process.
701 * @param line the commandline
702 */
703 private void processStartCommand( CommandLine line ) throws Exception
704 {
705 try
706 {
707 Manager manager = getManager( line );
708 String value = (String) line.getValue( START_COMMAND, null );
709 processStartCommand( manager, value );
710 }
711 catch( ConnectException ce )
712 {
713 final String message =
714 "\nCannot start application because the station is not running. "
715 + "\nUse 'station startup' to start the station process.";
716 System.out.println( message );
717 }
718 }
719
720 /**
721 * Handle a request for the startup of an application process.
722 * @param key the application key
723 */
724 private void processStartCommand( Manager manager, String key ) throws Exception
725 {
726 getLogger().info( "starting application [" + key + "]" );
727 Application application = manager.getApplication( key );
728 application.start();
729 }
730
731 /**
732 * Handle a request for control of an application process.
733 * @param line the commandline
734 */
735 private void processControlCommand( CommandLine line ) throws Exception
736 {
737 try
738 {
739 Manager manager = getManager( line );
740 String value = (String) line.getValue( CONTROL_COMMAND, null );
741 processControlCommand( manager, value );
742 }
743 catch( ConnectException ce )
744 {
745 final String message =
746 "\nCannot start application because the station is not running. "
747 + "\nUse 'station startup' to start the station process.";
748 System.out.println( message );
749 }
750 }
751
752 /**
753 * Handle a request for control of an application process.
754 * @param key the application key
755 */
756 private void processControlCommand( Manager manager, String key ) throws Exception
757 {
758 Application application = manager.getApplication( key );
759 InputStreamReader isr = new InputStreamReader( System.in );
760 BufferedReader reader = new BufferedReader( isr );
761 String line = null;
762 PID pid = application.getPID();
763 String prompt = "> ";
764 if( null != pid )
765 {
766 prompt = pid.toString() + "> ";
767 }
768
769 System.out.println( prompt + "Connected to application [" + key + "]" );
770 System.out.print( prompt );
771 Parser parser = new Parser();
772 parser.setGroup( CONTROLLER_GROUP );
773 while( ( line = reader.readLine() ) != null )
774 {
775 if( "".equals( line ) )
776 {
777 boolean ignoreLine = true;
778 }
779 else
780 {
781 try
782 {
783 String[] arguments = line.split( " " );
784 String[] args = expandArgs( arguments );
785 CommandLine commandline = parser.parse( args );
786 if( commandline.hasOption( CONTROL_HELP_COMMAND ) )
787 {
788 HelpFormatter formatter = new HelpFormatter();
789 formatter.setGroup( CONTROLLER_GROUP );
790 formatter.print();
791 }
792 else if( commandline.hasOption( CONTROL_EXIT_COMMAND ) )
793 {
794 System.exit( 0 );
795 }
796 else if( commandline.hasOption( CONTROL_INFO_COMMAND ) )
797 {
798 listInfo( application );
799 }
800 else if( commandline.hasOption( CONTROL_APPLY_COMMAND ) )
801 {
802 applyTransition( application, commandline );
803 }
804 else if( commandline.hasOption( CONTROL_EXEC_COMMAND ) )
805 {
806 execOperation( application, commandline );
807 }
808 else if( commandline.hasOption( CONTROL_INVOKE_COMMAND ) )
809 {
810 invokeOperation( application, commandline );
811 }
812 }
813 catch( Exception e )
814 {
815 System.out.println( e.getMessage() );
816 }
817 }
818 System.out.print( prompt );
819 }
820 }
821
822 private String[] expandArgs( String[] args )
823 {
824 String[] result = new String[ args.length ];
825 for( int i=0; i<args.length; i++ )
826 {
827 String arg = args[i];
828 String value = PropertyResolver.resolve( arg );
829 result[i] = value;
830 }
831 return result;
832 }
833
834 private String[] getExecArgs( CommandLine line )
835 {
836 return getArgs( CONTROL_EXEC_COMMAND, line );
837 }
838
839 private String[] getInvokeArgs( CommandLine line )
840 {
841 return getArgs( CONTROL_INVOKE_COMMAND, line );
842 }
843
844 private String[] getArgs( Option option, CommandLine line )
845 {
846 List args = line.getValues( option );
847 String[] elements = (String[]) args.toArray( new String[0] );
848 if( elements.length < 2 )
849 {
850 return new String[0];
851 }
852 String[] result = new String[ elements.length - 1 ];
853 for( int i=1; i<elements.length; i++ )
854 {
855 result[i-1] = elements[i];
856 }
857 return result;
858 }
859
860 private void listInfo( Application application ) throws Exception
861 {
862 System.out.println( "" );
863 Provider provider = application.getProvider();
864 if( null == provider )
865 {
866 System.out.println( "Provider unavailable." );
867 }
868 else
869 {
870 System.out.println( "Application: " + application.getID() );
871 State state = provider.getState();
872 System.out.println( "Current State: " + state );
873 Transition[] transitions = state.getTransitions();
874 System.out.println( "Transitions: " + transitions.length );
875 for( int i=0; i<transitions.length; i++ )
876 {
877 Transition transition = transitions[i];
878 System.out.println( " [" + ( i+1 ) + "] " + transition.getName() );
879 }
880 Operation[] operations = state.getOperations();
881 System.out.println( "Operations: " + operations.length );
882 for( int i=0; i<operations.length; i++ )
883 {
884 Operation operation = operations[i];
885 System.out.println( " [" + ( i+1 ) + "] " + operation.getName() );
886 }
887 Interface[] interfaces = state.getInterfaces();
888 System.out.println( "Interfaces: " + interfaces.length );
889 for( int i=0; i<interfaces.length; i++ )
890 {
891 System.out.println( " [" + ( i+1 ) + "] " + interfaces[i] );
892 }
893 }
894 System.out.println( "" );
895 }
896
897 private void applyTransition( Application application, CommandLine commandline ) throws Exception
898 {
899 String id = (String) commandline.getValue( CONTROL_APPLY_COMMAND, null );
900 System.out.println( "\napplying transition: " + id );
901 State state = application.getProvider().apply( id );
902 System.out.println( "current state: " + state );
903 System.out.println( "" );
904 }
905
906 private void invokeOperation( Application application, CommandLine commandline ) throws Exception
907 {
908 String method = (String) commandline.getValues( CONTROL_INVOKE_COMMAND ).get( 0 );
909 System.out.println( "\ninvoking operation: " + method );
910 try
911 {
912 String[] applyArgs = getInvokeArgs( commandline );
913 Object result = application.getProvider().invoke( method, applyArgs );
914 if( null != result )
915 {
916 System.out.println( "listing return value\n" );
917 if( result instanceof Object[] )
918 {
919 Object[] values = (Object[]) result;
920 for( int i=0; i<values.length; i++ )
921 {
922 System.out.println( values[i].toString() );
923 }
924 }
925 else
926 {
927 System.out.println( result.toString() );
928 }
929 System.out.println( "\ndone" );
930 }
931 else
932 {
933 System.out.println( "done" );
934 }
935 }
936 catch( InvocationTargetException e )
937 {
938 Throwable cause = e.getCause();
939 if( null != cause )
940 {
941 String error = ExceptionHelper.packException( cause, true );
942 System.out.println( error );
943 }
944 else
945 {
946 String error = ExceptionHelper.packException( e, true );
947 System.out.println( error );
948 }
949 }
950 catch( Throwable e )
951 {
952 System.out.println( e.toString() );
953 }
954 }
955
956 private void execOperation( Application application, CommandLine commandline ) throws Exception
957 {
958 String id = (String) commandline.getValues( CONTROL_EXEC_COMMAND ).get( 0 );
959 System.out.println( "\napplying operation: " + id );
960 try
961 {
962 String[] applyArgs = getExecArgs( commandline );
963 Object result = application.getProvider().exec( id, applyArgs );
964 if( null != result )
965 {
966 System.out.println( "listing return value\n" );
967 if( result instanceof Object[] )
968 {
969 Object[] values = (Object[]) result;
970 for( int i=0; i<values.length; i++ )
971 {
972 System.out.println( values[i].toString() );
973 }
974 }
975 else
976 {
977 System.out.println( result.toString() );
978 }
979 System.out.println( "\ndone" );
980 }
981 else
982 {
983 System.out.println( "done" );
984 }
985 }
986 catch( InvocationTargetException e )
987 {
988 Throwable cause = e.getCause();
989 if( null != cause )
990 {
991 String error = ExceptionHelper.packException( cause, true );
992 System.out.println( error );
993 }
994 else
995 {
996 String error = ExceptionHelper.packException( e, true );
997 System.out.println( error );
998 }
999 }
1000 catch( Throwable e )
1001 {
1002 System.out.println( e.toString() );
1003 }
1004 }
1005
1006 /**
1007 * Handle a request for the shutdown of an application process.
1008 * @param line the commandline
1009 */
1010 private void processStopCommand( CommandLine line ) throws Exception
1011 {
1012 try
1013 {
1014 Manager manager = getManager( line );
1015 String value = (String) line.getValue( STOP_COMMAND, null );
1016 processStopCommand( manager, value );
1017 }
1018 catch( ConnectException ce )
1019 {
1020 final String message =
1021 "\nCannot stop application because the station is not running. "
1022 + "\nUse 'station startup' to start the station process.";
1023 System.out.println( message );
1024 }
1025 }
1026
1027 /**
1028 * Handle a request for the shutdown of an application process.
1029 * @param key the application key
1030 */
1031 private void processStopCommand( Manager manager, String key ) throws Exception
1032 {
1033 getLogger().info( "stopping application [" + key + "]" );
1034 Application application = manager.getApplication( key );
1035 application.stop();
1036 }
1037
1038 /**
1039 * Handle a request for the restart of an application process.
1040 * @param line the commandline
1041 */
1042 private void processRestartCommand( CommandLine line ) throws Exception
1043 {
1044 try
1045 {
1046 Manager manager = getManager( line );
1047 String value = (String) line.getValue( RESTART_COMMAND, null );
1048 processRestartCommand( manager, value );
1049 }
1050 catch( ConnectException ce )
1051 {
1052 final String message =
1053 "\nCannot restart application because the station is not running. "
1054 + "\nUse 'station startup' to start the station process.";
1055 System.out.println( message );
1056 }
1057 }
1058
1059 /**
1060 * Handle a request for the restart of an application process.
1061 * @param key the application key
1062 */
1063 private void processRestartCommand( Manager manager, String key ) throws Exception
1064 {
1065 getLogger().info( "restarting application [" + key + "]" );
1066 Application application = manager.getApplication( key );
1067 application.restart();
1068 }
1069
1070 private void processAddCommand( CommandLine line ) throws Exception
1071 {
1072 ApplicationRegistry registry = getApplicationRegistry( line );
1073 String key = (String) line.getValue( ADD_COMMAND, null );
1074 URI uri = (URI) line.getValue( REQUIRED_URI_OPTION, null );
1075 Properties properties = getCommandLineProperties( line, new Properties() );
1076 String baseDir = getBasedir( line, null );
1077 String title = getTitle( line, key );
1078 StartupPolicy policy = getStartupPolicy( line, StartupPolicy.MANUAL );
1079 int startup = getStartupTimeout( line, ApplicationDescriptor.DEFAULT_STARTUP_TIMEOUT );
1080 int shutdown = getShutdownTimeout( line, ApplicationDescriptor.DEFAULT_SHUTDOWN_TIMEOUT );
1081 URI config = getConfigurationURI( line, null );
1082 processAddCommand(
1083 registry, key, title, uri, startup, shutdown, properties, baseDir, policy, config );
1084 }
1085
1086 /**
1087 * Add a profile to the registry.
1088 * @param key the application key
1089 * @param title the application title
1090 * @param uri the codebase uri
1091 * @param properties system properties
1092 * @param base process base directory
1093 * @param policy application startup policy
1094 */
1095 private void processAddCommand(
1096 ApplicationRegistry registry, String key, String title, URI uri,
1097 int startup, int shutdown, Properties properties, String base, StartupPolicy policy,
1098 URI config )
1099 {
1100 try
1101 {
1102 ApplicationDescriptor descriptor =
1103 new ApplicationDescriptor(
1104 uri,
1105 title,
1106 new ValueDirective[0],
1107 base,
1108 policy,
1109 startup,
1110 shutdown,
1111 properties,
1112 config );
1113 registry.addApplicationDescriptor( key, descriptor );
1114 registry.flush();
1115 System.out.println( "\nAdded new profile [" + key + "]" );
1116 listProfile( descriptor );
1117 }
1118 catch( DuplicateKeyException e )
1119 {
1120 final String error =
1121 "Cannot add application profile because the key ["
1122 + key
1123 + "] is already assigned to another profile.";
1124 getLogger().error( error );
1125 }
1126 catch( Throwable e )
1127 {
1128 final String error =
1129 "Unexpected error while processing add request.";
1130 getLogger().error( error, e );
1131 getLogger().error( Thread.currentThread().getContextClassLoader().toString() );
1132 }
1133 }
1134
1135 private void processSetCommand( CommandLine line ) throws Exception
1136 {
1137 ApplicationRegistry registry = getApplicationRegistry( line );
1138 String key = (String) line.getValue( SET_COMMAND, null );
1139 ApplicationDescriptor descriptor = registry.getApplicationDescriptor( key );
1140 URI uri = (URI) line.getValue( OPTIONAL_URI_OPTION, descriptor.getCodeBaseURI() );
1141 Properties properties = getCommandLineProperties( line, descriptor.getSystemProperties() );
1142 String baseDir = getBasedir( line, descriptor.getBasePath() );
1143 String title = getTitle( line, descriptor.getTitle() );
1144 StartupPolicy policy = getStartupPolicy( line, descriptor.getStartupPolicy() );
1145 int startup = getStartupTimeout( line, descriptor.getStartupTimeout() );
1146 int shutdown = getShutdownTimeout( line, descriptor.getShutdownTimeout() );
1147 URI config = getConfigurationURI( line, descriptor.getConfigurationURI() );
1148 processSetCommand(
1149 registry, descriptor, key, title, uri, startup, shutdown, properties, baseDir, policy, config );
1150 }
1151
1152 /**
1153 * Update a profile.
1154 * @param key the application key
1155 * @param title the application title
1156 * @param uri the codebase uri
1157 * @param properties system properties
1158 * @param base process base directory
1159 * @param policy application startup policy
1160 */
1161 private void processSetCommand(
1162 ApplicationRegistry registry, ApplicationDescriptor profile, String key, String title, URI uri,
1163 int startup, int shutdown, Properties properties, String base,
1164 StartupPolicy policy, URI config )
1165 throws IOException, UnknownKeyException
1166 {
1167 if( null == registry )
1168 {
1169 throw new NullPointerException( "registry" );
1170 }
1171 if( null == key )
1172 {
1173 throw new NullPointerException( "key" );
1174 }
1175 if( null == uri )
1176 {
1177 throw new NullPointerException( "uri" );
1178 }
1179 if( null == title )
1180 {
1181 throw new NullPointerException( "title" );
1182 }
1183 if( null == policy )
1184 {
1185 throw new NullPointerException( "policy" );
1186 }
1187 if( null == properties )
1188 {
1189 throw new NullPointerException( "properties" );
1190 }
1191 try
1192 {
1193 ApplicationDescriptor descriptor =
1194 new ApplicationDescriptor(
1195 uri,
1196 title,
1197 new ValueDirective[0],
1198 base,
1199 policy,
1200 startup,
1201 shutdown,
1202 properties,
1203 config );
1204 registry.updateApplicationDescriptor( key, descriptor );
1205 registry.flush();
1206 }
1207 catch( UnknownKeyException e )
1208 {
1209 final String error =
1210 "Cannot update application profile because the key ["
1211 + key
1212 + "] is unknown.";
1213 getLogger().error( error );
1214 }
1215 catch( Throwable e )
1216 {
1217 final String error =
1218 "Unexpected error while processing set command.";
1219 getLogger().error( error, e );
1220 getLogger().error( Thread.currentThread().getContextClassLoader().toString() );
1221 registry.updateApplicationDescriptor( key, profile );
1222 }
1223
1224 try
1225 {
1226 ApplicationDescriptor newProfile = registry.getApplicationDescriptor( key );
1227 System.out.println( "\nUpdated profile [" + key + "]" );
1228 listProfile( newProfile );
1229 }
1230 catch( UnknownKeyException e )
1231 {
1232 final String error =
1233 "Unexpected error - updated profile not found.";
1234 getLogger().error( error, e );
1235 }
1236 }
1237
1238 private void processRemoveCommand( CommandLine line ) throws Exception
1239 {
1240 ApplicationRegistry registry = getApplicationRegistry( line );
1241 String value = (String) line.getValue( REMOVE_COMMAND, null );
1242 try
1243 {
1244 Manager manager = getManager( line );
1245 Application application = manager.getApplication( value );
1246 application.stop();
1247 }
1248 catch( ConnectException ce )
1249 {
1250 boolean ignorable = true;
1251 }
1252 catch( UnknownKeyException ce )
1253 {
1254 boolean ignorable = true;
1255 }
1256 processRemoveCommand( registry, value );
1257 }
1258
1259 private void processRemoveCommand( ApplicationRegistry registry, String key )
1260 {
1261 try
1262 {
1263 registry.removeApplicationDescriptor( key );
1264 registry.flush();
1265 getLogger().info( "removed application [" + key + "]" );
1266 }
1267 catch( UnknownKeyException e )
1268 {
1269 final String error =
1270 "Cannot add application profile because the key ["
1271 + key
1272 + "] is unknown.";
1273 getLogger().error( error );
1274 }
1275 catch( Exception e )
1276 {
1277 final String error =
1278 "Unexpected error while processing remove request.";
1279 getLogger().error( error, e );
1280 }
1281 }
1282
1283 // ------------------------------------------------------------------------
1284 // internal utilities
1285 // ------------------------------------------------------------------------
1286
1287 private Logger getLogger()
1288 {
1289 return m_logger;
1290 }
1291
1292 private void logRawArguments( Logger logger, String[] args )
1293 {
1294 StringBuffer buffer =
1295 new StringBuffer(
1296 "Processing ["
1297 + args.length
1298 + "] args." );
1299 for( int i=0; i<args.length; i++ )
1300 {
1301 buffer.append(
1302 "\n "
1303 + ( i+1 )
1304 + " "
1305 + args[i] );
1306 }
1307 String message = buffer.toString();
1308 logger.debug( message );
1309 }
1310
1311 private String getRawArguments( String message, String[] args )
1312 {
1313 StringBuffer buffer = new StringBuffer( message );
1314 buffer.append( "\n command elements: " + args.length );
1315 for( int i=0; i<args.length; i++ )
1316 {
1317 buffer.append(
1318 "\n "
1319 + ( i+1 )
1320 + " "
1321 + args[i] );
1322 }
1323 return buffer.toString();
1324 }
1325
1326 private Station getStation( int port ) throws Exception
1327 {
1328 Registry registry = getLocalRegistry( port );
1329 if( null != registry )
1330 {
1331 try
1332 {
1333 return (Station) registry.lookup( Station.STATION_KEY );
1334 }
1335 catch( Throwable e )
1336 {
1337 return null;
1338 }
1339 }
1340 else
1341 {
1342 return null;
1343 }
1344 }
1345
1346 private ApplicationRegistry getApplicationRegistry( int port ) throws Exception
1347 {
1348 Station station = getStation( port );
1349 if( null != station )
1350 {
1351 Manager manager = (Manager) station;
1352 return manager.getApplicationRegistry();
1353 }
1354 else
1355 {
1356 return getApplicationRegistry( (URI) null );
1357 }
1358 }
1359
1360 private Registry getLocalRegistry( int port )
1361 {
1362 try
1363 {
1364 return LocateRegistry.getRegistry( port );
1365 }
1366 catch( RemoteException e )
1367 {
1368 return null;
1369 }
1370 }
1371
1372 private ApplicationRegistry getApplicationRegistry( URI uri ) throws IOException
1373 {
1374 if( null == uri )
1375 {
1376 return getLocalApplicationRegistry( ApplicationRegistry.DEFAULT_STORAGE_URI );
1377 }
1378 else if( uri.getScheme().startsWith( "registry:" ) )
1379 {
1380 return (ApplicationRegistry) Artifact.createArtifact( uri ).toURL().getContent();
1381 }
1382 else
1383 {
1384 return getLocalApplicationRegistry( uri );
1385 }
1386 }
1387
1388 /**
1389 * Create a new local application registry using the supplied uri.
1390 * As a side effect the internal state of this class is updated to reflect
1391 * the fact that this class is responsible for RMI cleanup.
1392 * @param uri the registry stoarage uri
1393 * @return the aplication registry
1394 */
1395 private ApplicationRegistry getLocalApplicationRegistry( URI uri )
1396 {
1397 try
1398 {
1399 Logger logger = getLogger();
1400 URL url = getStorageURL( uri );
1401 m_flag = true;
1402 m_registry = new RemoteApplicationRegistry( logger, url );
1403 return m_registry;
1404 }
1405 catch( Exception e )
1406 {
1407 final String error =
1408 "Unexpected error while loading application registry from the uri ["
1409 + uri
1410 + "].";
1411 getLogger().error( error, e );
1412 throw new RuntimeException( error, e );
1413 }
1414 }
1415
1416 /**
1417 * Return the storage uri as a url.
1418 * @param uri the uri
1419 * @return the url
1420 * @exception Exception if the uri could not be converted to a url
1421 */
1422 public URL getStorageURL( URI uri ) throws Exception
1423 {
1424 if( Artifact.isRecognized( uri ) )
1425 {
1426 return Artifact.createArtifact( uri ).toURL();
1427 }
1428 else
1429 {
1430 return uri.toURL();
1431 }
1432 }
1433
1434 /**
1435 * List infomation to console about the supplied profile.
1436 * @param profile the application profile
1437 */
1438 private void listProfile( ApplicationDescriptor profile )
1439 {
1440 StringBuffer buffer = new StringBuffer( "\n" );
1441 buffer.append( "\n Codebase: " + profile.getCodeBaseURI() );
1442 buffer.append( "\n Working Directory Path: " + profile.getBasePath() );
1443 buffer.append( "\n Startup Timeout: " + profile.getStartupTimeout() );
1444 buffer.append( "\n Shutdown Timeout: " + profile.getShutdownTimeout() );
1445 buffer.append( "\n Startup Policy: " + profile.getStartupPolicy() );
1446 Properties properties = profile.getSystemProperties();
1447 buffer.append( "\n System Properties: " + properties.size() );
1448 buffer.append( "\n" );
1449 System.out.println( buffer.toString() );
1450 }
1451
1452 // ------------------------------------------------------------------------
1453 // static utilities
1454 // ------------------------------------------------------------------------
1455
1456 private static final String DEPOT_STATION_PLUGIN_URI = "artifact:part:dpml/station/dpml-station-server#1.0.0";
1457 private static final Set STARTUP_POLICY_SET = createStartupPolicySet();
1458 private static final String[] SUPPORTED_URI_SCHEMES =
1459 new String[]{"link", "artifact", "local"};
1460
1461 private static final DefaultOptionBuilder OPTION_BUILDER = new DefaultOptionBuilder();
1462 private static final ArgumentBuilder ARGUMENT_BUILDER = new ArgumentBuilder();
1463 private static final CommandBuilder COMMAND_BUILDER = new CommandBuilder();
1464 private static final GroupBuilder GROUP_BUILDER = new GroupBuilder();
1465
1466 private static final Option STARTUP_POLICY_OPTION =
1467 OPTION_BUILDER
1468 .withShortName( "policy" )
1469 .withDescription( "Startup policy." )
1470 .withRequired( false )
1471 .withArgument(
1472 ARGUMENT_BUILDER
1473 .withDescription( "disabled|manual|automatic" )
1474 .withName( "policy" )
1475 .withMinimum( 1 )
1476 .withMaximum( 1 )
1477 .withValidator( new EnumValidator( STARTUP_POLICY_SET ) )
1478 .create() )
1479 .create();
1480
1481 private static final Option BASEDIR_OPTION =
1482 OPTION_BUILDER
1483 .withShortName( "dir" )
1484 .withShortName( "basedir" )
1485 .withDescription( "Base directory." )
1486 .withRequired( false )
1487 .withArgument(
1488 ARGUMENT_BUILDER
1489 .withDescription( "Directory path." )
1490 .withName( "path" )
1491 .withMinimum( 1 )
1492 .withMaximum( 1 )
1493 .create() )
1494 .create();
1495
1496 private static final Option TITLE_OPTION =
1497 OPTION_BUILDER
1498 .withShortName( "title" )
1499 .withDescription( "Application title." )
1500 .withRequired( false )
1501 .withArgument(
1502 ARGUMENT_BUILDER
1503 .withDescription( "Description." )
1504 .withName( "title" )
1505 .withMinimum( 1 )
1506 .withMaximum( 1 )
1507 .create() )
1508 .create();
1509
1510 private static final PropertyOption PROPERTY_OPTION = new PropertyOption();
1511 private static final Option REQUIRED_URI_OPTION = buildURIOption( true );
1512 private static final Option OPTIONAL_URI_OPTION = buildURIOption( false );
1513 private static final NumberValidator INTERGER_VALIDATOR = NumberValidator.getIntegerInstance();
1514
1515 private static final Option REGISTRY_URI_OPTION =
1516 OPTION_BUILDER
1517 .withShortName( "registry" )
1518 .withDescription( "Application registry store." )
1519 .withRequired( false )
1520 .withArgument(
1521 ARGUMENT_BUILDER
1522 .withDescription( "Local or remote artifact reference." )
1523 .withName( "artifact" )
1524 .withMinimum( 1 )
1525 .withMaximum( 1 )
1526 .withValidator( new URIValidator() )
1527 .create() )
1528 .create();
1529
1530 private static final Option CONFIGURATION_URI_OPTION =
1531 OPTION_BUILDER
1532 .withShortName( "config" )
1533 .withDescription( "Application configuration." )
1534 .withRequired( false )
1535 .withArgument(
1536 ARGUMENT_BUILDER
1537 .withDescription( "Configuration uri." )
1538 .withName( "uri" )
1539 .withMinimum( 1 )
1540 .withMaximum( 1 )
1541 .withValidator( new URIValidator() )
1542 .create() )
1543 .create();
1544
1545 private static final Option PORT_OPTION =
1546 OPTION_BUILDER
1547 .withShortName( "port" )
1548 .withDescription( "RMI Registry port." )
1549 .withRequired( false )
1550 .withArgument(
1551 ARGUMENT_BUILDER
1552 .withDescription( "Registry port." )
1553 .withName( "port" )
1554 .withMinimum( 0 )
1555 .withMaximum( 1 )
1556 .withValidator( INTERGER_VALIDATOR )
1557 .create() )
1558 .create();
1559
1560 private static final Option STARTUP_TIMEOUT_OPTION =
1561 OPTION_BUILDER
1562 .withShortName( "startup" )
1563 .withDescription( "Startup timeout." )
1564 .withRequired( false )
1565 .withArgument(
1566 ARGUMENT_BUILDER
1567 .withDescription( "Timeout in seconds." )
1568 .withName( "seconds" )
1569 .withMinimum( 1 )
1570 .withMaximum( 1 )
1571 .withValidator( INTERGER_VALIDATOR )
1572 .create() )
1573 .create();
1574
1575 private static final Option SHUTDOWN_TIMEOUT_OPTION =
1576 OPTION_BUILDER
1577 .withShortName( "shutdown" )
1578 .withDescription( "Shutdown timeout." )
1579 .withRequired( false )
1580 .withArgument(
1581 ARGUMENT_BUILDER
1582 .withDescription( "Timeout in seconds." )
1583 .withName( "seconds" )
1584 .withMinimum( 1 )
1585 .withMaximum( 1 )
1586 .withValidator( INTERGER_VALIDATOR )
1587 .create() )
1588 .create();
1589
1590 private static final Group APPLICATION_REGISTRY_GROUP =
1591 GROUP_BUILDER
1592 .withMinimum( 0 )
1593 .withMaximum( 1 )
1594 .withOption( PORT_OPTION )
1595 .withOption( REGISTRY_URI_OPTION )
1596 .create();
1597
1598 private static final Group STARTUP_GROUP =
1599 GROUP_BUILDER
1600 .withMinimum( 0 )
1601 .withMaximum( 2 )
1602 .withOption( PORT_OPTION )
1603 .withOption( REGISTRY_URI_OPTION )
1604 .withOption( PROPERTY_OPTION )
1605 .create();
1606
1607 private static final Option STARTUP_COMMAND =
1608 COMMAND_BUILDER
1609 .withName( "startup" )
1610 .withDescription( "Startup the station." )
1611 .withChildren( STARTUP_GROUP )
1612 .create();
1613
1614 private static final Option SHUTDOWN_COMMAND =
1615 COMMAND_BUILDER
1616 .withName( "shutdown" )
1617 .withDescription( "Shutdown the station." )
1618 .create();
1619
1620 private static final Option HELP_COMMAND =
1621 COMMAND_BUILDER
1622 .withName( "help" )
1623 .withDescription( "Print command help." )
1624 .create();
1625
1626 private static final Group ADD_OPTIONS_GROUP =
1627 GROUP_BUILDER
1628 .withMinimum( 1 )
1629 .withOption( REQUIRED_URI_OPTION )
1630 .withOption( STARTUP_POLICY_OPTION )
1631 .withOption( PROPERTY_OPTION )
1632 .withOption( BASEDIR_OPTION )
1633 .withOption( TITLE_OPTION )
1634 .withOption( REGISTRY_URI_OPTION )
1635 .withOption( STARTUP_TIMEOUT_OPTION )
1636 .withOption( SHUTDOWN_TIMEOUT_OPTION )
1637 .withOption( CONFIGURATION_URI_OPTION )
1638 .create();
1639
1640 private static final Option ADD_COMMAND =
1641 COMMAND_BUILDER
1642 .withName( "add" )
1643 .withDescription( "Add a profile." )
1644 .withArgument(
1645 ARGUMENT_BUILDER
1646 .withDescription( "Unique application key." )
1647 .withName( "key" )
1648 .withMinimum( 1 )
1649 .withMaximum( 1 )
1650 .create() )
1651 .withChildren( ADD_OPTIONS_GROUP )
1652 .create();
1653
1654 private static final Group SET_OPTIONS_GROUP =
1655 GROUP_BUILDER
1656 .withMinimum( 0 )
1657 .withOption( OPTIONAL_URI_OPTION )
1658 .withOption( STARTUP_POLICY_OPTION )
1659 .withOption( PROPERTY_OPTION )
1660 .withOption( BASEDIR_OPTION )
1661 .withOption( TITLE_OPTION )
1662 .withOption( REGISTRY_URI_OPTION )
1663 .withOption( STARTUP_TIMEOUT_OPTION )
1664 .withOption( SHUTDOWN_TIMEOUT_OPTION )
1665 .withOption( CONFIGURATION_URI_OPTION )
1666 .create();
1667
1668 private static final Option SET_COMMAND =
1669 COMMAND_BUILDER
1670 .withName( "set" )
1671 .withDescription( "Set an application feature." )
1672 .withArgument(
1673 ARGUMENT_BUILDER
1674 .withDescription( "application key" )
1675 .withName( "key" )
1676 .withMinimum( 1 )
1677 .withMaximum( 1 )
1678 .create() )
1679 .withChildren( SET_OPTIONS_GROUP )
1680 .create();
1681
1682 private static final Option CONTROL_COMMAND =
1683 COMMAND_BUILDER
1684 .withName( "control" )
1685 .withDescription( "Interactive control of an application." )
1686 .withArgument(
1687 ARGUMENT_BUILDER
1688 .withDescription( "application key" )
1689 .withName( "key" )
1690 .withMinimum( 1 )
1691 .withMaximum( 1 )
1692 .create() )
1693 .create();
1694
1695 private static final Option START_COMMAND =
1696 COMMAND_BUILDER
1697 .withName( "start" )
1698 .withDescription( "Start application." )
1699 .withArgument(
1700 ARGUMENT_BUILDER
1701 .withDescription( "Application key." )
1702 .withName( "key" )
1703 .withMinimum( 1 )
1704 .withMaximum( 1 )
1705 .create() )
1706 .create();
1707
1708 private static final Option STOP_COMMAND =
1709 COMMAND_BUILDER
1710 .withName( "stop" )
1711 .withDescription( "Stop application." )
1712 .withArgument(
1713 ARGUMENT_BUILDER
1714 .withDescription( "Application key." )
1715 .withName( "key" )
1716 .withMinimum( 1 )
1717 .withMaximum( 1 )
1718 .create() )
1719 .create();
1720
1721 private static final Option RESTART_COMMAND =
1722 COMMAND_BUILDER
1723 .withName( "restart" )
1724 .withDescription( "Restart application." )
1725 .withArgument(
1726 ARGUMENT_BUILDER
1727 .withDescription( "Application key." )
1728 .withName( "key" )
1729 .withMinimum( 1 )
1730 .withMaximum( 1 )
1731 .create() )
1732 .create();
1733
1734 private static final Option REMOVE_COMMAND =
1735 COMMAND_BUILDER
1736 .withName( "remove" )
1737 .withDescription( "Remove profile." )
1738 .withArgument(
1739 ARGUMENT_BUILDER
1740 .withDescription( "unique application key" )
1741 .withName( "key" )
1742 .withMinimum( 1 )
1743 .withMaximum( 1 )
1744 .create() )
1745 .withChildren( APPLICATION_REGISTRY_GROUP )
1746 .create();
1747
1748 private static final Option INFO_COMMAND =
1749 COMMAND_BUILDER
1750 .withName( "info" )
1751 .withDescription( "Station or profile info." )
1752 .withArgument(
1753 ARGUMENT_BUILDER
1754 .withDescription( "Application key." )
1755 .withName( "key" )
1756 .withMinimum( 0 )
1757 .withMaximum( 1 )
1758 .create() )
1759 .withChildren( APPLICATION_REGISTRY_GROUP )
1760 .create();
1761
1762 private static final Group COMMAND_GROUP =
1763 GROUP_BUILDER
1764 .withName( "options" )
1765 .withOption( STARTUP_COMMAND )
1766 .withOption( ADD_COMMAND )
1767 .withOption( SET_COMMAND )
1768 .withOption( START_COMMAND )
1769 .withOption( CONTROL_COMMAND )
1770 .withOption( STOP_COMMAND )
1771 .withOption( RESTART_COMMAND )
1772 .withOption( INFO_COMMAND )
1773 .withOption( REMOVE_COMMAND )
1774 .withOption( SHUTDOWN_COMMAND )
1775 .withOption( HELP_COMMAND )
1776 .withMinimum( 1 )
1777 .withMaximum( 1 )
1778 .create();
1779
1780 // micro control cli spec
1781
1782 private static final Option CONTROL_INFO_COMMAND =
1783 COMMAND_BUILDER
1784 .withName( "info" )
1785 .withDescription( "List state info." )
1786 .create();
1787
1788 private static final Option CONTROL_EXIT_COMMAND =
1789 COMMAND_BUILDER
1790 .withName( "exit" )
1791 .withDescription( "Exit the console." )
1792 .create();
1793
1794 private static final Option CONTROL_APPLY_COMMAND =
1795 COMMAND_BUILDER
1796 .withName( "apply" )
1797 .withDescription( "Apply a state transition." )
1798 .withArgument(
1799 ARGUMENT_BUILDER
1800 .withDescription( "Transition name." )
1801 .withName( "id" )
1802 .withMinimum( 1 )
1803 .withMaximum( 1 )
1804 .create() )
1805 .create();
1806
1807 private static final Option CONTROL_EXEC_COMMAND =
1808 COMMAND_BUILDER
1809 .withName( "exec" )
1810 .withDescription( "Execute a management operation." )
1811 .withArgument(
1812 ARGUMENT_BUILDER
1813 .withDescription( "Operation name." )
1814 .withName( "id" )
1815 .withMinimum( 1 )
1816 .create() )
1817 .create();
1818
1819 private static final Option CONTROL_INVOKE_COMMAND =
1820 COMMAND_BUILDER
1821 .withName( "invoke" )
1822 .withDescription( "Invoke a management operation." )
1823 .withArgument(
1824 ARGUMENT_BUILDER
1825 .withDescription( "Operation name." )
1826 .withName( "method" )
1827 .withMinimum( 1 )
1828 .create() )
1829 .create();
1830
1831 private static final Option CONTROL_HELP_COMMAND =
1832 COMMAND_BUILDER
1833 .withName( "help" )
1834 .withDescription( "List controller help info." )
1835 .create();
1836
1837 private static final Group CONTROLLER_GROUP =
1838 GROUP_BUILDER
1839 .withName( "options" )
1840 .withOption( CONTROL_INFO_COMMAND )
1841 .withOption( CONTROL_APPLY_COMMAND )
1842 .withOption( CONTROL_INVOKE_COMMAND )
1843 .withOption( CONTROL_EXEC_COMMAND )
1844 .withOption( CONTROL_EXIT_COMMAND )
1845 .withOption( CONTROL_HELP_COMMAND )
1846 .withMinimum( 1 )
1847 .withMaximum( 1 )
1848 .create();
1849
1850 private static Option buildURIOption( boolean required )
1851 {
1852 return OPTION_BUILDER
1853 .withShortName( "uri" )
1854 .withDescription( "Codebase uri." )
1855 .withRequired( required )
1856 .withArgument(
1857 ARGUMENT_BUILDER
1858 .withDescription( "Codebase uri." )
1859 .withName( "artifact" )
1860 .withMinimum( 1 )
1861 .withMaximum( 1 )
1862 .withValidator( new URIValidator() )
1863 .create() )
1864 .create();
1865 }
1866
1867 private static Set createStartupPolicySet()
1868 {
1869 Set set = new HashSet();
1870 StartupPolicy[] values = StartupPolicy.values();
1871 for( int i=0; i<values.length; i++ )
1872 {
1873 StartupPolicy policy = values[i];
1874 set.add( policy.getName() );
1875 }
1876 return set;
1877 }
1878 }
1879